#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <assert.h>
#include <ctype.h>

#include "ILexer.h"
#include "Scintilla.h"
#include "SciLexer.h"

#include "WordList.h"
#include "LexAccessor.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "CharacterSet.h"
#include "LexerModule.h"

#ifdef SCI_NAMESPACE
using namespace Scintilla;
#endif


static inline bool IsNewline( const int ch );
static int GetHexaNibble( char hd );
static int GetHexaChar( char hd1, char hd2 );
static int GetHexaChar( unsigned int pos, Accessor &styler );
static bool ForwardWithinLine( StyleContext &sc, int nb = 1 );
static bool PosInSameRecord( unsigned int pos1, unsigned int pos2, Accessor &styler );
static int CountByteCount( unsigned int startPos, int uncountedDigits, Accessor &styler );
static int CalcChecksum( unsigned int startPos, int cnt, bool twosCompl, Accessor &styler );


static unsigned int GetSrecRecStartPosition( unsigned int pos, Accessor &styler );
static int GetSrecByteCount( unsigned int recStartPos, Accessor &styler );
static int CountSrecByteCount( unsigned int recStartPos, Accessor &styler );
static int GetSrecAddressFieldSize( unsigned int recStartPos, Accessor &styler );
static int GetSrecAddressFieldType( unsigned int recStartPos, Accessor &styler );
static int GetSrecDataFieldType( unsigned int recStartPos, Accessor &styler );
static int GetSrecRequiredDataFieldSize( unsigned int recStartPos, Accessor &styler );
static int GetSrecChecksum( unsigned int recStartPos, Accessor &styler );
static int CalcSrecChecksum( unsigned int recStartPos, Accessor &styler );

static unsigned int GetIHexRecStartPosition( unsigned int pos, Accessor &styler );
static int GetIHexByteCount( unsigned int recStartPos, Accessor &styler );
static int CountIHexByteCount( unsigned int recStartPos, Accessor &styler );
static int GetIHexAddressFieldType( unsigned int recStartPos, Accessor &styler );
static int GetIHexDataFieldType( unsigned int recStartPos, Accessor &styler );
static int GetIHexRequiredDataFieldSize( unsigned int recStartPos, Accessor &styler );
static int GetIHexChecksum( unsigned int recStartPos, Accessor &styler );
static int CalcIHexChecksum( unsigned int recStartPos, Accessor &styler );

static int GetTEHexDigitCount( unsigned int recStartPos, Accessor &styler );
static int CountTEHexDigitCount( unsigned int recStartPos, Accessor &styler );
static int GetTEHexAddressFieldType( unsigned int recStartPos, Accessor &styler );
static int GetTEHexChecksum( unsigned int recStartPos, Accessor &styler );
static int CalcTEHexChecksum( unsigned int recStartPos, Accessor &styler );

static inline bool IsNewline( const int ch ) {
  return ( ch == '\n' || ch == '\r' );
}

static int GetHexaNibble( char hd ) {
  int hexValue = 0;
  if( hd >= '0' && hd <= '9' ) {
    hexValue += hd - '0';
  } else if( hd >= 'A' && hd <= 'F' ) {
    hexValue += hd - 'A' + 10;
  } else if( hd >= 'a' && hd <= 'f' ) {
    hexValue += hd - 'a' + 10;
  } else {
    return -1;
  }
  return hexValue;
}

static int GetHexaChar( char hd1, char hd2 ) {
  int hexValue = 0;
  if( hd1 >= '0' && hd1 <= '9' ) {
    hexValue += 16 * ( hd1 - '0' );
  } else if( hd1 >= 'A' && hd1 <= 'F' ) {
    hexValue += 16 * ( hd1 - 'A' + 10 );
  } else if( hd1 >= 'a' && hd1 <= 'f' ) {
    hexValue += 16 * ( hd1 - 'a' + 10 );
  } else {
    return -1;
  }
  if( hd2 >= '0' && hd2 <= '9' ) {
    hexValue += hd2 - '0';
  } else if( hd2 >= 'A' && hd2 <= 'F' ) {
    hexValue += hd2 - 'A' + 10;
  } else if( hd2 >= 'a' && hd2 <= 'f' ) {
    hexValue += hd2 - 'a' + 10;
  } else {
    return -1;
  }
  return hexValue;
}

static int GetHexaChar( unsigned int pos, Accessor &styler ) {
  char highNibble, lowNibble;
  highNibble = styler.SafeGetCharAt( pos );
  lowNibble = styler.SafeGetCharAt( pos + 1 );
  return GetHexaChar( highNibble, lowNibble );
}





static bool ForwardWithinLine( StyleContext &sc, int nb ) {
  for( int i = 0; i < nb; i++ ) {
    if( sc.atLineEnd ) {
      sc.SetState( SCE_HEX_DEFAULT );
      sc.Forward();
      return false;
    } else
    { sc.Forward(); }
  }
  return true;
}


static bool PosInSameRecord( unsigned int pos1, unsigned int pos2, Accessor &styler ) {
  return styler.GetLine( pos1 ) == styler.GetLine( pos2 );
}




static int CountByteCount( unsigned int startPos, int uncountedDigits, Accessor &styler ) {
  int cnt;
  unsigned int pos;
  pos = startPos;
  while( !IsNewline( styler.SafeGetCharAt( pos, '\n' ) ) ) {
    pos++;
  }
  cnt = static_cast<int>( pos - startPos ) - uncountedDigits;
  if( cnt >= 0 ) {
    cnt++;
  }
  cnt /= 2;
  return cnt;
}




static int CalcChecksum( unsigned int startPos, int cnt, bool twosCompl, Accessor &styler ) {
  int cs = 0;
  for( unsigned int pos = startPos; pos < startPos + cnt; pos += 2 ) {
    int val = GetHexaChar( pos, styler );
    if( val < 0 ) {
      return val;
    }
    cs += val;
  }
  if( twosCompl ) {
    return -cs & 0xFF;
  } else {
    return ~cs & 0xFF;
  }
}



static unsigned int GetSrecRecStartPosition( unsigned int pos, Accessor &styler ) {
  while( styler.SafeGetCharAt( pos ) != 'S' ) {
    pos--;
  }
  return pos;
}



static int GetSrecByteCount( unsigned int recStartPos, Accessor &styler ) {
  int val;
  val = GetHexaChar( recStartPos + 2, styler );
  if( val < 0 ) {
    val = 0;
  }
  return val;
}




static int CountSrecByteCount( unsigned int recStartPos, Accessor &styler ) {
  return CountByteCount( recStartPos, 4, styler );
}


static int GetSrecAddressFieldSize( unsigned int recStartPos, Accessor &styler ) {
  switch( styler.SafeGetCharAt( recStartPos + 1 ) ) {
    case '0':
    case '1':
    case '5':
    case '9':
      return 2;
    case '2':
    case '6':
    case '8':
      return 3;
    case '3':
    case '7':
      return 4;
    default:
      return 0;
  }
}


static int GetSrecAddressFieldType( unsigned int recStartPos, Accessor &styler ) {
  switch( styler.SafeGetCharAt( recStartPos + 1 ) ) {
    case '0':
      return SCE_HEX_NOADDRESS;
    case '1':
    case '2':
    case '3':
      return SCE_HEX_DATAADDRESS;
    case '5':
    case '6':
      return SCE_HEX_RECCOUNT;
    case '7':
    case '8':
    case '9':
      return SCE_HEX_STARTADDRESS;
    default:
      return SCE_HEX_ADDRESSFIELD_UNKNOWN;
  }
}


static int GetSrecDataFieldType( unsigned int recStartPos, Accessor &styler ) {
  switch( styler.SafeGetCharAt( recStartPos + 1 ) ) {
    case '0':
    case '1':
    case '2':
    case '3':
      return SCE_HEX_DATA_ODD;
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
      return SCE_HEX_DATA_EMPTY;
    default:
      return SCE_HEX_DATA_UNKNOWN;
  }
}




static int GetSrecRequiredDataFieldSize( unsigned int recStartPos, Accessor &styler ) {
  switch( styler.SafeGetCharAt( recStartPos + 1 ) ) {
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
      return 0;
    default:
      return GetSrecByteCount( recStartPos, styler )
             - GetSrecAddressFieldSize( recStartPos, styler )
             - 1;
  }
}


static int GetSrecChecksum( unsigned int recStartPos, Accessor &styler ) {
  int byteCount;
  byteCount = GetSrecByteCount( recStartPos, styler );
  return GetHexaChar( recStartPos + 2 + byteCount * 2, styler );
}


static int CalcSrecChecksum( unsigned int recStartPos, Accessor &styler ) {
  int byteCount;
  byteCount = GetSrecByteCount( recStartPos, styler );
  return CalcChecksum( recStartPos + 2, byteCount * 2, false, styler );
}



static unsigned int GetIHexRecStartPosition( unsigned int pos, Accessor &styler ) {
  while( styler.SafeGetCharAt( pos ) != ':' ) {
    pos--;
  }
  return pos;
}



static int GetIHexByteCount( unsigned int recStartPos, Accessor &styler ) {
  int val;
  val = GetHexaChar( recStartPos + 1, styler );
  if( val < 0 ) {
    val = 0;
  }
  return val;
}




static int CountIHexByteCount( unsigned int recStartPos, Accessor &styler ) {
  return CountByteCount( recStartPos, 11, styler );
}


static int GetIHexAddressFieldType( unsigned int recStartPos, Accessor &styler ) {
  if( !PosInSameRecord( recStartPos, recStartPos + 7, styler ) ) {
    return SCE_HEX_ADDRESSFIELD_UNKNOWN;
  }
  switch( GetHexaChar( recStartPos + 7, styler ) ) {
    case 0x00:
      return SCE_HEX_DATAADDRESS;
    case 0x01:
    case 0x02:
    case 0x03:
    case 0x04:
    case 0x05:
      return SCE_HEX_NOADDRESS;
    default:
      return SCE_HEX_ADDRESSFIELD_UNKNOWN;
  }
}


static int GetIHexDataFieldType( unsigned int recStartPos, Accessor &styler ) {
  switch( GetHexaChar( recStartPos + 7, styler ) ) {
    case 0x00:
      return SCE_HEX_DATA_ODD;
    case 0x01:
      return SCE_HEX_DATA_EMPTY;
    case 0x02:
    case 0x04:
      return SCE_HEX_EXTENDEDADDRESS;
    case 0x03:
    case 0x05:
      return SCE_HEX_STARTADDRESS;
    default:
      return SCE_HEX_DATA_UNKNOWN;
  }
}



static int GetIHexRequiredDataFieldSize( unsigned int recStartPos, Accessor &styler ) {
  switch( GetHexaChar( recStartPos + 7, styler ) ) {
    case 0x01:
      return 0;
    case 0x02:
    case 0x04:
      return 2;
    case 0x03:
    case 0x05:
      return 4;
    default:
      return GetIHexByteCount( recStartPos, styler );
  }
}


static int GetIHexChecksum( unsigned int recStartPos, Accessor &styler ) {
  int byteCount;
  byteCount = GetIHexByteCount( recStartPos, styler );
  return GetHexaChar( recStartPos + 9 + byteCount * 2, styler );
}


static int CalcIHexChecksum( unsigned int recStartPos, Accessor &styler ) {
  int byteCount;
  byteCount = GetIHexByteCount( recStartPos, styler );
  return CalcChecksum( recStartPos + 1, 8 + byteCount * 2, true, styler );
}




static int GetTEHexDigitCount( unsigned int recStartPos, Accessor &styler ) {
  int val = GetHexaChar( recStartPos + 1, styler );
  if( val < 0 ) {
    val = 0;
  }
  return val;
}



static int CountTEHexDigitCount( unsigned int recStartPos, Accessor &styler ) {
  unsigned int pos;
  pos = recStartPos + 1;
  while( !IsNewline( styler.SafeGetCharAt( pos, '\n' ) ) ) {
    pos++;
  }
  return static_cast<int>( pos - ( recStartPos + 1 ) );
}


static int GetTEHexAddressFieldType( unsigned int recStartPos, Accessor &styler ) {
  switch( styler.SafeGetCharAt( recStartPos + 3 ) ) {
    case '6':
      return SCE_HEX_DATAADDRESS;
    case '8':
      return SCE_HEX_STARTADDRESS;
    default:
      return SCE_HEX_ADDRESSFIELD_UNKNOWN;
  }
}


static int GetTEHexChecksum( unsigned int recStartPos, Accessor &styler ) {
  return GetHexaChar( recStartPos + 4, styler );
}


static int CalcTEHexChecksum( unsigned int recStartPos, Accessor &styler ) {
  unsigned int pos = recStartPos + 1;
  unsigned int length = GetTEHexDigitCount( recStartPos, styler );
  int cs = GetHexaNibble( styler.SafeGetCharAt( pos++ ) );
  cs += GetHexaNibble( styler.SafeGetCharAt( pos++ ) );
  cs += GetHexaNibble( styler.SafeGetCharAt( pos++ ) );
  pos += 2;
  for( ; pos <= recStartPos + length; ++pos ) {
    int val = GetHexaNibble( styler.SafeGetCharAt( pos ) );
    if( val < 0 ) {
      return val;
    }
    cs += val;
  }
  return cs & 0xFF;
}

static void ColouriseSrecDoc( unsigned int startPos, int length, int initStyle, WordList *[], Accessor &styler ) {
  StyleContext sc( startPos, length, initStyle, styler );
  while( sc.More() ) {
    unsigned int recStartPos;
    int byteCount, reqByteCount, addrFieldSize, addrFieldType, dataFieldSize, dataFieldType;
    int cs1, cs2;
    switch( sc.state ) {
      case SCE_HEX_DEFAULT:
        if( sc.atLineStart && sc.Match( 'S' ) ) {
          sc.SetState( SCE_HEX_RECSTART );
        }
        ForwardWithinLine( sc );
        break;
      case SCE_HEX_RECSTART:
        recStartPos = sc.currentPos - 1;
        addrFieldType = GetSrecAddressFieldType( recStartPos, styler );
        if( addrFieldType == SCE_HEX_ADDRESSFIELD_UNKNOWN ) {
          sc.SetState( SCE_HEX_RECTYPE_UNKNOWN );
        } else
        { sc.SetState( SCE_HEX_RECTYPE ); }
        ForwardWithinLine( sc );
        break;
      case SCE_HEX_RECTYPE:
      case SCE_HEX_RECTYPE_UNKNOWN:
        recStartPos = sc.currentPos - 2;
        byteCount = GetSrecByteCount( recStartPos, styler );
        reqByteCount = GetSrecAddressFieldSize( recStartPos, styler )
                       + GetSrecRequiredDataFieldSize( recStartPos, styler )
                       + 1;
        if( byteCount == CountSrecByteCount( recStartPos, styler )
            && byteCount == reqByteCount ) {
          sc.SetState( SCE_HEX_BYTECOUNT );
        } else
        { sc.SetState( SCE_HEX_BYTECOUNT_WRONG ); }
        ForwardWithinLine( sc, 2 );
        break;
      case SCE_HEX_BYTECOUNT:
      case SCE_HEX_BYTECOUNT_WRONG:
        recStartPos = sc.currentPos - 4;
        addrFieldSize = GetSrecAddressFieldSize( recStartPos, styler );
        addrFieldType = GetSrecAddressFieldType( recStartPos, styler );
        sc.SetState( addrFieldType );
        ForwardWithinLine( sc, addrFieldSize * 2 );
        break;
      case SCE_HEX_NOADDRESS:
      case SCE_HEX_DATAADDRESS:
      case SCE_HEX_RECCOUNT:
      case SCE_HEX_STARTADDRESS:
      case SCE_HEX_ADDRESSFIELD_UNKNOWN:
        recStartPos = GetSrecRecStartPosition( sc.currentPos, styler );
        dataFieldType = GetSrecDataFieldType( recStartPos, styler );
        dataFieldSize = GetSrecRequiredDataFieldSize( recStartPos, styler );
        sc.SetState( dataFieldType );
        if( dataFieldType == SCE_HEX_DATA_ODD ) {
          for( int i = 0; i < dataFieldSize * 2; i++ ) {
            if( ( i & 0x3 ) == 0 )
            { sc.SetState( SCE_HEX_DATA_ODD ); }
            else if( ( i & 0x3 ) == 2 )
            { sc.SetState( SCE_HEX_DATA_EVEN ); }
            if( !ForwardWithinLine( sc ) )
            { break; }
          }
        } else
        { ForwardWithinLine( sc, dataFieldSize * 2 ); }
        break;
      case SCE_HEX_DATA_ODD:
      case SCE_HEX_DATA_EVEN:
      case SCE_HEX_DATA_EMPTY:
      case SCE_HEX_DATA_UNKNOWN:
        recStartPos = GetSrecRecStartPosition( sc.currentPos, styler );
        cs1 = CalcSrecChecksum( recStartPos, styler );
        cs2 = GetSrecChecksum( recStartPos, styler );
        if( cs1 != cs2 || cs1 < 0 || cs2 < 0 ) {
          sc.SetState( SCE_HEX_CHECKSUM_WRONG );
        } else
        { sc.SetState( SCE_HEX_CHECKSUM ); }
        ForwardWithinLine( sc, 2 );
        break;
      case SCE_HEX_CHECKSUM:
      case SCE_HEX_CHECKSUM_WRONG:
      case SCE_HEX_GARBAGE:
        sc.SetState( SCE_HEX_GARBAGE );
        ForwardWithinLine( sc );
        break;
      default:
        sc.SetState( SCE_HEX_DEFAULT );
        break;
    }
  }
  sc.Complete();
}

static void ColouriseIHexDoc( unsigned int startPos, int length, int initStyle, WordList *[], Accessor &styler ) {
  StyleContext sc( startPos, length, initStyle, styler );
  while( sc.More() ) {
    unsigned int recStartPos;
    int byteCount, addrFieldType, dataFieldSize, dataFieldType;
    int cs1, cs2;
    switch( sc.state ) {
      case SCE_HEX_DEFAULT:
        if( sc.atLineStart && sc.Match( ':' ) ) {
          sc.SetState( SCE_HEX_RECSTART );
        }
        ForwardWithinLine( sc );
        break;
      case SCE_HEX_RECSTART:
        recStartPos = sc.currentPos - 1;
        byteCount = GetIHexByteCount( recStartPos, styler );
        dataFieldSize = GetIHexRequiredDataFieldSize( recStartPos, styler );
        if( byteCount == CountIHexByteCount( recStartPos, styler )
            && byteCount == dataFieldSize ) {
          sc.SetState( SCE_HEX_BYTECOUNT );
        } else
        { sc.SetState( SCE_HEX_BYTECOUNT_WRONG ); }
        ForwardWithinLine( sc, 2 );
        break;
      case SCE_HEX_BYTECOUNT:
      case SCE_HEX_BYTECOUNT_WRONG:
        recStartPos = sc.currentPos - 3;
        addrFieldType = GetIHexAddressFieldType( recStartPos, styler );
        sc.SetState( addrFieldType );
        ForwardWithinLine( sc, 4 );
        break;
      case SCE_HEX_NOADDRESS:
      case SCE_HEX_DATAADDRESS:
      case SCE_HEX_ADDRESSFIELD_UNKNOWN:
        recStartPos = sc.currentPos - 7;
        addrFieldType = GetIHexAddressFieldType( recStartPos, styler );
        if( addrFieldType == SCE_HEX_ADDRESSFIELD_UNKNOWN ) {
          sc.SetState( SCE_HEX_RECTYPE_UNKNOWN );
        } else
        { sc.SetState( SCE_HEX_RECTYPE ); }
        ForwardWithinLine( sc, 2 );
        break;
      case SCE_HEX_RECTYPE:
      case SCE_HEX_RECTYPE_UNKNOWN:
        recStartPos = sc.currentPos - 9;
        dataFieldType = GetIHexDataFieldType( recStartPos, styler );
        dataFieldSize = GetIHexRequiredDataFieldSize( recStartPos, styler );
        sc.SetState( dataFieldType );
        if( dataFieldType == SCE_HEX_DATA_ODD ) {
          for( int i = 0; i < dataFieldSize * 2; i++ ) {
            if( ( i & 0x3 ) == 0 )
            { sc.SetState( SCE_HEX_DATA_ODD ); }
            else if( ( i & 0x3 ) == 2 )
            { sc.SetState( SCE_HEX_DATA_EVEN ); }
            if( !ForwardWithinLine( sc ) )
            { break; }
          }
        } else
        { ForwardWithinLine( sc, dataFieldSize * 2 ); }
        break;
      case SCE_HEX_DATA_ODD:
      case SCE_HEX_DATA_EVEN:
      case SCE_HEX_DATA_EMPTY:
      case SCE_HEX_EXTENDEDADDRESS:
      case SCE_HEX_STARTADDRESS:
      case SCE_HEX_DATA_UNKNOWN:
        recStartPos = GetIHexRecStartPosition( sc.currentPos, styler );
        cs1 = CalcIHexChecksum( recStartPos, styler );
        cs2 = GetIHexChecksum( recStartPos, styler );
        if( cs1 != cs2 || cs1 < 0 || cs2 < 0 ) {
          sc.SetState( SCE_HEX_CHECKSUM_WRONG );
        } else
        { sc.SetState( SCE_HEX_CHECKSUM ); }
        ForwardWithinLine( sc, 2 );
        break;
      case SCE_HEX_CHECKSUM:
      case SCE_HEX_CHECKSUM_WRONG:
      case SCE_HEX_GARBAGE:
        sc.SetState( SCE_HEX_GARBAGE );
        ForwardWithinLine( sc );
        break;
      default:
        sc.SetState( SCE_HEX_DEFAULT );
        break;
    }
  }
  sc.Complete();
}

static void FoldIHexDoc( unsigned int startPos, int length, int, WordList *[], Accessor &styler ) {
  unsigned int endPos = startPos + length;
  int lineCurrent = styler.GetLine( startPos );
  int levelCurrent = SC_FOLDLEVELBASE;
  if( lineCurrent > 0 ) {
    levelCurrent = styler.LevelAt( lineCurrent - 1 );
  }
  unsigned int lineStartNext = styler.LineStart( lineCurrent + 1 );
  int levelNext = SC_FOLDLEVELBASE;
  for( unsigned int i = startPos; i < endPos; i++ ) {
    bool atEOL = i == ( lineStartNext - 1 );
    int style = styler.StyleAt( i );
    if( style == SCE_HEX_EXTENDEDADDRESS ) {
      levelNext = SC_FOLDLEVELBASE | SC_FOLDLEVELHEADERFLAG;
    } else if( style == SCE_HEX_DATAADDRESS
               || ( style == SCE_HEX_DEFAULT
                    && i == ( unsigned int )styler.LineStart( lineCurrent ) ) ) {
      if( levelCurrent & SC_FOLDLEVELHEADERFLAG ) {
        levelNext = SC_FOLDLEVELBASE + 1;
      } else
      { levelNext = levelCurrent; }
    }
    if( atEOL || ( i == endPos - 1 ) ) {
      styler.SetLevel( lineCurrent, levelNext );
      lineCurrent++;
      lineStartNext = styler.LineStart( lineCurrent + 1 );
      levelCurrent = levelNext;
      levelNext = SC_FOLDLEVELBASE;
    }
  }
}

static void ColouriseTEHexDoc( unsigned int startPos, int length, int initStyle, WordList *[], Accessor &styler ) {
  StyleContext sc( startPos, length, initStyle, styler );
  while( sc.More() ) {
    unsigned int recStartPos;
    int digitCount, addrFieldType;
    int cs1, cs2;
    switch( sc.state ) {
      case SCE_HEX_DEFAULT:
        if( sc.atLineStart && sc.Match( '%' ) ) {
          sc.SetState( SCE_HEX_RECSTART );
        }
        ForwardWithinLine( sc );
        break;
      case SCE_HEX_RECSTART:
        recStartPos = sc.currentPos - 1;
        if( GetTEHexDigitCount( recStartPos, styler ) == CountTEHexDigitCount( recStartPos, styler ) ) {
          sc.SetState( SCE_HEX_BYTECOUNT );
        } else
        { sc.SetState( SCE_HEX_BYTECOUNT_WRONG ); }
        ForwardWithinLine( sc, 2 );
        break;
      case SCE_HEX_BYTECOUNT:
      case SCE_HEX_BYTECOUNT_WRONG:
        recStartPos = sc.currentPos - 3;
        addrFieldType = GetTEHexAddressFieldType( recStartPos, styler );
        if( addrFieldType == SCE_HEX_ADDRESSFIELD_UNKNOWN ) {
          sc.SetState( SCE_HEX_RECTYPE_UNKNOWN );
        } else
        { sc.SetState( SCE_HEX_RECTYPE ); }
        ForwardWithinLine( sc );
        break;
      case SCE_HEX_RECTYPE:
      case SCE_HEX_RECTYPE_UNKNOWN:
        recStartPos = sc.currentPos - 4;
        cs1 = CalcTEHexChecksum( recStartPos, styler );
        cs2 = GetTEHexChecksum( recStartPos, styler );
        if( cs1 != cs2 || cs1 < 0 || cs2 < 0 ) {
          sc.SetState( SCE_HEX_CHECKSUM_WRONG );
        } else
        { sc.SetState( SCE_HEX_CHECKSUM ); }
        ForwardWithinLine( sc, 2 );
        break;
      case SCE_HEX_CHECKSUM:
      case SCE_HEX_CHECKSUM_WRONG:
        recStartPos = sc.currentPos - 6;
        addrFieldType = GetTEHexAddressFieldType( recStartPos, styler );
        sc.SetState( addrFieldType );
        ForwardWithinLine( sc, 9 );
        break;
      case SCE_HEX_DATAADDRESS:
      case SCE_HEX_STARTADDRESS:
      case SCE_HEX_ADDRESSFIELD_UNKNOWN:
        recStartPos = sc.currentPos - 15;
        digitCount = GetTEHexDigitCount( recStartPos, styler ) - 14;
        sc.SetState( SCE_HEX_DATA_ODD );
        for( int i = 0; i < digitCount; i++ ) {
          if( ( i & 0x3 ) == 0 ) {
            sc.SetState( SCE_HEX_DATA_ODD );
          } else if( ( i & 0x3 ) == 2 ) {
            sc.SetState( SCE_HEX_DATA_EVEN );
          }
          if( !ForwardWithinLine( sc ) ) {
            break;
          }
        }
        break;
      case SCE_HEX_DATA_ODD:
      case SCE_HEX_DATA_EVEN:
      case SCE_HEX_GARBAGE:
        sc.SetState( SCE_HEX_GARBAGE );
        ForwardWithinLine( sc );
        break;
      default:
        sc.SetState( SCE_HEX_DEFAULT );
        break;
    }
  }
  sc.Complete();
}

LexerModule lmSrec( SCLEX_SREC, ColouriseSrecDoc, "srec", 0, NULL );
LexerModule lmIHex( SCLEX_IHEX, ColouriseIHexDoc, "ihex", FoldIHexDoc, NULL );
LexerModule lmTEHex( SCLEX_TEHEX, ColouriseTEHexDoc, "tehex", 0, NULL );
